package cn.itsource.hrm.service.impl;

import cn.itsource.hrm.config.HighlightResultMapper;
import cn.itsource.hrm.document.CourseDoc;
import cn.itsource.hrm.query.CourseQuery;
import cn.itsource.hrm.repository.CourseRepostory;
import cn.itsource.hrm.result.AggrAjaxResult;
import cn.itsource.hrm.service.ISearcherService;
import cn.itsource.hrm.utils.AjaxResult;
import cn.itsource.hrm.utils.PageList;
import cn.itsource.hrm.vo.AggrObjectVo;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SearcherServiceImpl implements ISearcherService {
    @Autowired
    private CourseRepostory courseRepostory;

    @Autowired
    private ElasticsearchTemplate template;

    /**
     * 将课程保存到ES中
     * @param courseDoc
     */
    @Override
    public void save (CourseDoc courseDoc) {
        courseRepostory.save(courseDoc);
    }

    /**
     * 到ES中搜索课程
     * @param query
     * @return
     */
    @Override
    public AggrAjaxResult searchCourse(CourseQuery query) {
        //1. 准备 SearchQueryBuilder
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

        // 2 boolQuery 判断参数的条件
        boolQueryReady(query, searchQueryBuilder, boolQueryBuilder);

        //3. 分页 : page rows
        searchQueryBuilder.withPageable(PageRequest.of(query.getPage()-1, query.getRows()));

        //4. 排序 sortField sortType ======================================================
        sortQuery(query, searchQueryBuilder);

        //5. 高亮查询
        HighlightBuilder.Field field =  new HighlightBuilder.Field("name").preTags("<b style='color:red'>").postTags("</b>");
        searchQueryBuilder.withHighlightFields(field);

        //6. 聚合查询
        TermsAggregationBuilder terms_count_grade = AggregationBuilders.terms("count_grade")
                .field("gradeName").order(Terms.Order.count(false));
        searchQueryBuilder.addAggregation(terms_count_grade);

        TermsAggregationBuilder count_tenant = AggregationBuilders.terms("count_tenant")
                .field("tenantName").order(Terms.Order.count(false));
        searchQueryBuilder.addAggregation(count_tenant);


        // 构建SearchQuery 进行查询
        NativeSearchQuery searchQuery = searchQueryBuilder.build();
        // Page<CourseDoc> search = courseRepostory.search(searchQuery);
        AggregatedPage<CourseDoc> search = template.queryForPage(searchQuery, CourseDoc.class, new HighlightResultMapper());

        // search 查询聚合结果 封装Ajax对象
        AggrAjaxResult aggrAjaxResult = new AggrAjaxResult();
        StringTerms tenantNameAggTerms = (StringTerms)search.getAggregation("count_tenant");
        StringTerms gradeNameAggTerms = (StringTerms)search.getAggregation("count_grade");

        List<AggrObjectVo> aggrTenantNames = tenantNameAggTerms.getBuckets().stream().map(bucket ->
                new AggrObjectVo(bucket.getKeyAsString(),bucket.getDocCount())
        ).collect(Collectors.toList());

        List<AggrObjectVo> aggrGrades = gradeNameAggTerms.getBuckets().stream().map(bucket ->
                new AggrObjectVo(bucket.getKeyAsString(),bucket.getDocCount())
        ).collect(Collectors.toList());

//        List<StringTerms.Bucket> buckets =
//        buckets.forEach(bucket -> {
//            AggrObjectVo aggrTenant = new AggrObjectVo();
//            aggrTenant.setName(bucket.getKeyAsString());
//            aggrTenant.setNumber(bucket.getDocCount());
//            aggrTenantNames.add(aggrTenant);
//        });
//
//        List<AggrObjectVo> aggrGrades =new ArrayList<>();
//        StringTerms gradeNameAggTerms = (StringTerms)search.getAggregation("count_grade");
//        List<StringTerms.Bucket> buckets2 = gradeNameAggTerms.getBuckets();
//        buckets2.forEach(bucket -> {
//            AggrObjectVo aggrGrade = new AggrObjectVo();
//            aggrGrade.setName(bucket.getKeyAsString());
//            aggrGrade.setNumber(bucket.getDocCount());
//            aggrGrades.add(aggrGrade);
//        });

        aggrAjaxResult.setAggrGrades(aggrGrades);
        aggrAjaxResult.setAggrTenantNames(aggrTenantNames);

        // 查询结果的转换
        PageList<CourseDoc> pageList = new PageList<>();
        pageList.setRows(search.getContent()); // 数据
        pageList.setTotal(search.getTotalElements()); // 总条数

        log.info("查询结果：{}",pageList.getRows());

        aggrAjaxResult.setResultObj(pageList);
        return aggrAjaxResult;
    }

    private void sortQuery(CourseQuery query, NativeSearchQueryBuilder searchQueryBuilder) {
        // 排序的字段先准备 变量
        String fieldName = "onLineTime";
        SortOrder asc = SortOrder.DESC;

        String sortField = query.getSortField();
        String sortType = query.getSortType();
        if(sortField!=null){
            switch (sortField){
                case "xl": fieldName = "viewCount"; break;
                case "pl": fieldName = "priceOld"; break;
                case "jg": fieldName = "price"; break;
                case "rq": fieldName = "viewCount"; break;
                default:  fieldName = "onLineTime";
            }
        }

        if(sortType!=null) {
            asc = sortType.equals("desc") ? SortOrder.DESC : SortOrder.ASC;
        }

        searchQueryBuilder.withSort(new FieldSortBuilder(fieldName).order(asc));
    }

    private void boolQueryReady(CourseQuery query, NativeSearchQueryBuilder searchQueryBuilder, BoolQueryBuilder boolQueryBuilder) {
        //must   keyword  =====================================
        if(!StringUtils.isEmpty(query.getKeyword())){
            // TermQueryBuilder 不分词 查询
            boolQueryBuilder.must(new TermQueryBuilder("name", query.getKeyword()));

        }else{
            //  MatchAllQueryBuilder 查询所有
            boolQueryBuilder.must(new MatchAllQueryBuilder());
        }


        //filter  price 价格范围查询
        if (query.getPriceMin()!=null){
            boolQueryBuilder.filter(new RangeQueryBuilder("price").gte(query.getPriceMin()));
        }

        if (query.getPriceMax()!=null){
            boolQueryBuilder.filter(new RangeQueryBuilder("price").lte(query.getPriceMax()));
        }

        // courseTypeId, gradeId    tenantId

        searchQueryBuilder.withQuery(boolQueryBuilder);
    }

}
